import Jexl  from "jexl";
import { cloneDeep, isNumber, get } from "lodash";
import { ElMessage } from "element-plus";
import { isJSON } from "@/utils/util"

// 表达式操作符及其分组信息
const OPERATOR_WITH_GROUP = {
  "calculation": [
    { label: "＋", value: "+", desc: "加法运算、拼接字符串" },
    { label: "－", value: "-", desc: "减法运算" },
    { label: "×", value: "*", desc: "乘法运算" },
    { label: "÷", value: "/", desc: "除法运算" },
    { label: "(", value: "(", desc: "左括号" },
    { label: ")", value: ")", desc: "右括号" },
    { label: ",", value: ",", desc: "逗号，参数分隔符" }
  ],
  "relation": [
    { label: ">", value: ">", desc: "大于" },
    { label: ">=", value: ">=", desc: "大于等于" },
    { label: "<", value: "<", desc: "小于" },
    { label: "<=", value: "<=", desc: "小于等于" },
    { label: "等于", value: "==", desc: "左右两侧是否相等" },
    { label: "不等于", value: "!=", desc: "左右两侧是否不相等" },
    { label: "包含", value: "INCLUDES()", desc: "首个参数是否包含第二个参数" },
    { label: "不包含", value: "NOT_INCLUDED()", desc: "首参数是不否包含第二个参数" }
  ],
  "logic": [
    { label: "且", value: "&&", desc: "并且连接，等价于 '&&'" },
    { label: "或", value: "||", desc: "或者连接，等价于 '||'" },
    { label: "非", value: "!", desc: "取反操作，等价于 '!'" }
  ],
  "math": [
    { label: "求和", value: "SUM()", desc: "对所有参数求和" },
    { label: "求差", value: "SUBTRACT()", desc: "对所有参数求差" },
    { label: "乘积", value: "MULTIPLY()", desc: "对所有参数求乘积" },
    { label: "求商", value: "DIVIDE()", desc: "对所有参数求商" },
    { label: "绝对值", value: "ABS()", desc: "获取指定数字的绝对值" },
    { label: "最大值", value: "MAX()", desc: "获取所有参数中最大值" },
    { label: "最小值", value: "MIN()", desc: "获取所有参数中最小值" },
    { label: "平均值", value: "AVERAGE()", desc: "获取所有参数的平均值" }
  ],
  "other": [
    { label: "中文大写金额", value: "AMOUNT_TO_CHINESE()", desc: "将金额转换为中文大写格式" },
    { label: "中文大写数字", value: "NUMBER_TO_CHINESE()", desc: "将数字转换为中文大写格式" },
    { label: "日期差", value: "DAYS_DIFFERENCE()", desc: "获取两个日期相差天数（目前仅支持时间戳格式）" },
    { label: "日期时间差", value: "TIME_DIFFERENCE()", desc: "获取两个日期时间差值，精确至小时和分钟（目前仅支持时间戳格式）" },
  ]
};

// 注册 Jexl 自定义函数
Jexl.addFunctions({
  "INCLUDES": (...args) => {
    if (args.length < 2) {
      throw new Error(`表达式解析异常：函数 'INCLUDES' 需要 2 参数，但只找到 ${ args.length } 个`);
    }
    const source = args[0], target = args[1];
    return source.includes(target);
  },
  "NOT_INCLUDED": (...args) => {
    if (args.length < 2) {
      throw new Error(`表达式解析异常：函数 'NOT_INCLUDED' 需要 2 参数，但只找到 ${ args.length } 个`);
    }
    const source = args[0], target = args[1];
    return !source.includes(target);
  },
  "SUM": (...args) => {
    if (args.length < 1) {
      throw new Error(`表达式解析异常：函数 'SUM' 需要 1 参数，但只找到 ${ args.length } 个`);
    }
    return args.reduce((prev, next) => (prev + next))
  },
  "SUBTRACT": (...args) => args.reduce((prev, next) => (prev - next)),
  "MULTIPLY": (...args) => args.reduce((prev, next) => (prev * next)),
  "DIVIDE": (...args) => {
    if (args.length > 1) {
      return args.reduce((prev, next) => {
        // 检查除数是否为0
        if (next === 0) {
          return 0
        }
        return prev / next;
      });
    }
  },
  "MAX": (...args) => Math.max(...args),
  "MIN": (...args) => Math.min(...args),
  "ABS": (...args) => Math.abs(...args),
  "AVERAGE": (...args) => (args.reduce((prev, next) => (prev + next)) / args.length),
  "AMOUNT_TO_CHINESE": (...args) => {
    let result = "";
    if (args.length > 0) {
      try {
        result = ExpressionUtil.amountToChinese(args[0]);
      } catch (error) {
        throw new Error(`表达式解析异常：${ error }`);
      }
    }
    return result;
  },
  "NUMBER_TO_CHINESE": (...args) => {
    let result = "";
    if (args.length > 0) {
      try {
        result = ExpressionUtil.numberToChinese(args[0]);
      } catch (error) {
        throw new Error(`表达式解析异常：${ error }`);
      }
    }
    return result;
  },
  "DAYS_DIFFERENCE": (...args) => {
    if (args.length < 2) {
      throw new Error(`表达式解析异常：函数 'DAYS_DIFFERENCE' 需要 2 参数，但只找到 ${ args.length } 个`);
    }
    if (!args.every(item => !!item)) {
      return 0;
      // throw new Error(`表达式解析异常：参数为空值，无法计算日期差`);
    }
    const date1 = new Date(args[0]), date2 = new Date(args[1]);
    return Math.abs(date1 - date2) / (24 * 60 * 60 * 1000);
  },
  "TIME_DIFFERENCE": (...args) => {
    if (args.length < 2) {
      throw new Error(`表达式解析异常：函数 'TIME_DIFFERENCE' 需要 2 个参数，但只找到 ${args.length} 个`);
    }
    if (!args.every(item => !!item)) {
      return { days: 0, hours: 0, minutes: 0 };
      // throw new Error(`表达式解析异常：参数为空值，无法计算时间差`);
    }
    const date1 = new Date(args[0]), date2 = new Date(args[1]);
    const diffTime = Math.abs(date1 - date2); // 获取两个日期之间的毫秒差
    const days = Math.floor(diffTime / (24 * 60 * 60 * 1000)); // 计算天数
    const hours = Math.floor((diffTime % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000)); // 计算剩余的小时数
    const minutes = Math.floor((diffTime % (60 * 60 * 1000)) / (60 * 1000)); // 计算剩余的分钟数
    // 返回对象
    // const result = { days, hours, minutes };
    // 返回格式化字符串
    // const formattedString = `${days}天${hours}小时${minutes}分钟`;
    let formattedString = "";
    if (days > 0) formattedString += `${days}天`;
    if (hours > 0 || days > 0) formattedString += `${hours}小时`;
    if (minutes > 0 || hours > 0 || days > 0) formattedString += `${minutes}分钟`;
    return formattedString || "0分钟"
  },
});


// 中文大写数字
const CHINESE_DIGITS = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
// 中文大写较小单位
const CHINESE_UNITS = ["仟", "佰", "拾", ""];
// 中文大写较大单位
const CHINESE_SECTIONS = ["元", "万", "亿", "万亿"];

/**
 * 分割整数字符串为四字节
 * @param intStr {string}
 */
const splitIntStrSections = (intStr) => {
  const intStrSections = [];

  const reversed = intStr.split("").reverse().join("");
  for (let i = 0; i < reversed.length; i += 4) {
    let section = reversed.substr(i, 4);
    section = section.split("").reverse().join("").padStart(4, "0");
    intStrSections.push(section);
  }

  return intStrSections.reverse();
};

/**
 * 将四字节数字转换四位中文大写
 * @param intStr {string}
 */
const convertFourDigits = (intStr) => {
  let result = "", prevZero = false;

  for (let i = 0; i < 4; i++) {
    const num = parseInt(intStr[i], 10);
    if (num === 0) {
      prevZero = true;
    } else {
      if (prevZero && result) result += "零";
      result += CHINESE_DIGITS[num] + CHINESE_UNITS[i];
      prevZero = false;
    }
  }

  return result || "";
}

/**
 * 将整数部分转换为中文大写
 * @param intStr {string}
 */
const convertInteger = (intStr) => {
  let result = "";

  const intStrSections = splitIntStrSections(intStr);
  for (let i = 0; i < intStrSections.length; i++) {
    const section = intStrSections[i];
    const sectionChinese = convertFourDigits(section);
    if (sectionChinese) {
      const unitIndex = intStrSections.length - 1 - i;
      result += sectionChinese + (CHINESE_SECTIONS[unitIndex] || "");
    }
  }

  // 添加元或处理零元
  if (!result) return "零元";
  if (!result.endsWith("元")) result += "元";
  return result;
};

/**
 * 将小数部分转换为中文大写
 * @param decimalStr {string}
 */
const convertDecimal = (decimalStr) => {
  const jiao = decimalStr[0], fen = decimalStr[1];

  if (jiao === "0" && fen === "0") return "整";
  if (jiao !== "0" && fen === "0") return CHINESE_DIGITS[jiao] + "角整";
  if (jiao === "0" && fen !== "0") return `零${ CHINESE_DIGITS[fen] }分`;
  return `${ CHINESE_DIGITS[jiao] }角${ CHINESE_DIGITS[fen] }分`;
}

/**
 * 处理负数
 * @param {*} value 
 * @returns 
 */
const handleNegativeNum = (value) => {
  if (typeof value == "number") {
    return value < 0 ? `(${value})` : value
  } else if (Array.isArray(value)) {
    return value.map(item => item.name || item.mainName)
  } else if (typeof value == "object" && value != null) {
    return value.name
  } else if (isJSON(value) && Array.isArray(JSON.parse(value))) {
    return JSON.parse(value).map(item => item.name)
  } else {
    return (value == null || value == undefined) ? "" : value
  }
}

/**
 * 表达式构建及解析工具类
 */
export default class ExpressionUtil {

  // 表达式操作符及其分组信息
  static OPERATOR_WITH_GROUP = OPERATOR_WITH_GROUP;

  /**
   * 获取简单表达式中包含的字段
   * @param expression {string} 表达式字符串
   * @return formFields {string[]} 返回当前表达式中涉及到的字段名
   */
  static getFieldsInSimpleExpression = (expression = "") => {
    const matchResult = expression.match(/\$\{([^}]+)\}/g);
    return matchResult ? Array.from(matchResult).map((item) => {
      return item.substring(2, item.length - 1).trim();
    }) : [];
  };

  /**
   * 获取高级表达式中包含的字段
   * @param expressionGroup {Record<string, any>[]} 高级表达式字符串组
   * @return formFields {string[]} 返回当前表达式组中涉及到的字段名
   */
  static getFieldsInAdvancedExpression = (expressionGroup = []) => {
    const result = [];

    const [ elseItem, ...frontItems ] = cloneDeep(expressionGroup).reverse();
    frontItems.forEach((item) => {
      const conditionMatchResult = item.condition?.match(/\$\{([^}]+)\}/g);
      !!conditionMatchResult && Array.from(conditionMatchResult).forEach((str) => {
        const fieldName = str.substring(2, str.length - 1).trim();
        !result.includes(fieldName) && result.push(fieldName);
      });

      const contentMatchResult = item.content?.match(/\$\{([^}]+)\}/g);
      !!contentMatchResult && Array.from(contentMatchResult).forEach((str) => {
        const fieldName = str.substring(2, str.length - 1).trim();
        !result.includes(fieldName) && result.push(fieldName);
      });
    });

    const elseMatchResult = elseItem.content?.match(/\$\{([^}]+)\}/g);
    !!elseMatchResult && Array.from(elseMatchResult).forEach((str) => {
      const fieldName = str.substring(2, str.length - 1).trim();
      !result.includes(fieldName) && result.push(fieldName);
    });

    return result;
  };

  /**
   * 解析简单表达式字符串
   * @param expression {string} 表达式字符串
   * @param object {object} 表单数据（formData）
   * @param subRecordIndex {number} 明细表计算行数（表达式不涉及明细表字段值时不需要传）
   */
  static evalSimpleExpression = (expression = "", object = {}, subRecordIndex) => {
    let expressionStr = expression;
    ExpressionUtil.getFieldsInSimpleExpression(expression).forEach((field) => {
      let fieldValue = "";
      if (field.includes(".")) {
        const [ subFormName, subFieldName ] = field.split(".");
        // fieldValue = get(object, `${ subFormName }[${ subRecordIndex }].zhlx_gjz_subform_value.${ subFieldName }[0].defaultValue`);
        // fieldValue = object[subFormName][subRecordIndex][subFieldName];
        // debugger
        if (subRecordIndex !== undefined) {
          fieldValue = handleNegativeNum(object[subFormName][subRecordIndex][subFieldName]);
        } else {
          let arr = object[subFormName].map((item) => handleNegativeNum(item[subFieldName]));
          fieldValue = arr.length ? arr : 0;
        }
      } else {
        // fieldValue = get(object, `${ field }[0].defaultValue`);
        fieldValue = handleNegativeNum(object[field]);
      }
      expressionStr = expressionStr.replaceAll(`\${${ field }}`, fieldValue);
    });

    let expressionResult = null;
    if (expressionStr) {
      try {
        const res = Jexl.evalSync(expressionStr, {})
        expressionResult = Number.isNaN(res) ? 0 : res;
      } catch (error) {
        console.error(error);
        // ElMessage.error({
        //   message: error
        // });
      }
    }
    return expressionResult;
  };

  /**
   * 解析高级表达式字符串
   * @param expressionGroup {Record<string, any>[]} 高级表达式字符串组
   * @param object {object} 表单数据（formData）
   * @param subRecordIndex {number} 明细表计算行数（表达式不涉及明细表字段值时不需要传）
   */
  static evalAdvancedExpression = (expressionGroup = [], object = {}, subRecordIndex) => {
    const [ elseItem, ...frontItems ] = cloneDeep(expressionGroup).reverse();
    // 获取条件解析结果为 true 的表达式配置项
    const effectiveItem = frontItems.reverse().find((item) => {
      return !!ExpressionUtil.evalSimpleExpression(item.condition, object, subRecordIndex);
    });

    const { content } = effectiveItem ? effectiveItem : elseItem;
    return ExpressionUtil.evalSimpleExpression(content, object, subRecordIndex);
  };

  /**
   * 将金额转换为中文大写
   * @param value {number | string}
   */
  static amountToChinese = (value) => {
    // 处理非数字或负数的情况
    const amountNum = typeof value === "number" ? value : parseFloat(value);
    if (isNaN(amountNum) || (amountNum < 0)) {
      throw new Error("金额转换输入无效");
    }

    // 转换为两位小数并分割整数和小数部分
    const amountStr = amountNum.toFixed(2).toString();
    const [integerPart, decimalPart = "00"] = amountStr.split(".");

    // 合并结果: 整数部分 + 小数部分
    return convertInteger(integerPart) + convertDecimal(decimalPart);
  };

  /**
   * 将数字转换为中文大写
   * @param value {number | string}
   */
  static numberToChinese = (value) => {
    // 处理非数字或负数的情况
    const targetNum = typeof value === "number" ? value : parseFloat(value);
    if (isNaN(targetNum) || (targetNum < 0)) {
      throw new Error("数字转换输入无效");
    }

    return targetNum.toString().split("").map((item) => {
      return (item === ".") ? "点" : CHINESE_DIGITS[item];
    }).join("");
  };

}
